﻿package com.game.tips
{
	
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.filters.DisplacementMapFilter;
	import flash.geom.Point;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFormat;
	import flash.utils.Dictionary;
	/**
	 * 
	 * @author zengly
	 * 
	 */	
	public class TipCtrl extends Sprite
	{
		private var _parent:Sprite;
		private var _floatTipDic:Dictionary;
		private var _targets:Dictionary;
		private var _target:DisplayObject;
		private var _content:DisplayObject;
		private var _contentOffset:Point;
		private var _contentSpan:Point;
		private var _mouseOffset:Point;
		private var _dir:int = 0;
		private var _tempX:Number = 0;
		private var _tempY:Number = 0;
		private var _txtTween:TextField;
		private var _speed:Number = 0.08;
		private var _stageW:uint;
		private var _stageH:uint
		private static var _offset:Point = new Point(0, 0);
		private static var _obj:TipCtrl;
		public static const LEFT:int = -1;
		public static const RIGHT:int = 1;
		
		public function TipCtrl()
		{
			_targets = new Dictionary();
			_floatTipDic = new Dictionary();
			_contentOffset = new Point(6, 6);
			_contentSpan = new Point(10, 0);
			_mouseOffset = new Point(15, 15);
			mouseEnabled = false;
			initTextTip();
		}
		
		public function set stageH(value:uint):void
		{
			_stageH = value;
		}

		public function set stageW(value:uint):void
		{
			_stageW = value;
		}

		public function get stageOffset():Point
		{
			return _offset;
		}
		/**
		 * 添加提示信息 
		 * @param target 所要添加的目标
		 * @param content 添加的内容 字符串 或者 显示对象
		 * @param needBg 需不需要默认的背景
		 * 
		 */		
		public function addTarget(target:DisplayObject, content:Object = null, needBg:Boolean = true):void
		{
			clearTarget(target);
			addOne(target, content, needBg);
			addEvent(target);
		}
		/**
		 * 添加多个提示 
		 * @param target
		 * @param args
		 * 
		 */		
		public function addTargetMoreTips(target:DisplayObject, ... args):void
		{
			clearTarget(target);
			for(var i:int = 0; i < args.length; i++)
				addOne(target, args[i], true);
			addEvent(target);
		}
		/**
		 * 添加固定提示，  
		 * @param target
		 * @param content
		 * @param point
		 * @param needBg
		 * @param topBase
		 * 
		 */		
		public function addFixedTarget(target:DisplayObject, content:Object, point:Point, needBg:Boolean = true, topBase:Boolean = true):void
		{
			clearTarget(target);
			addOne(target, content, needBg, point, topBase);
			addEvent(target);
		}
		
		private function addOne(target:DisplayObject, content:Object, needBg:Boolean = true, pos:Point = null, topBase:Boolean = true):void
		{
			var d:DisplayObject;
			if (content is String)
			{
				d = new TextField();
				with (d as TextField)
				{
					selectable = false;
					autoSize = TextFieldAutoSize.LEFT;
					multiline = true;
					htmlText = content;
				}
			}
			else if (content is DisplayObject)
			{
				d = content as DisplayObject;
			}
			if (_targets[target] == null)
			{
				_targets[target] = {contents:[], pos:pos, topBase:topBase, needBg:needBg};
			}
			_targets[target]["contents"].push(d);
		}
		
		public function removeTarget(target:DisplayObject):void
		{
			if (target && _targets[target])
			{
				hide();
				removeEvent(target);
				delete _targets[target];
			}
		}
		
		private function addEvent(target:DisplayObject):void
		{
			var mouseMove:Function = function (event:MouseEvent):void
			{
				if (stage == null)
					return;
				_target = target;
				if (!_targets[target] || !_targets[target]["contents"])
					return;
				
				var d:DisplayObject = _targets[target]["contents"][0];
				if (_content && _content != d)
				{
					while (numChildren)
					{
						removeChildAt(0);
					}
					_content = null;
				}
				if (_content != d)
				{
					_content = d;
					
					var len:int = _targets[target]["contents"].length;
					for(var i:int = 0; i < len; i++)
					{
						d = _targets[target]["contents"][i];
						addChild(d);
					}
					draw();
				}
				var tipX:Number = _parent.mouseX + _mouseOffset.x;
				var tipY:Number = _parent.mouseY + _mouseOffset.y;
				if (tipX + width > _stageW - _offset.x * 2)
				{
					tipX = _parent.mouseX - width - _mouseOffset.x + 5;
					var dir:int  = TipCtrl.LEFT;
				}
				else
				{
					dir = TipCtrl.RIGHT;
				}
				if (tipY + height > _stageH - _offset.y * 2)
				{
					tipY = _parent.mouseY - height - _mouseOffset.y + 5;
				}
				if (tipY < _mouseOffset.y)
				{
					tipY = _mouseOffset.y;
				}
				if (_targets[target].pos != null)
				{
					x = _targets[target].pos.x;
					y = _targets[target].pos.y - height;
				}
				else
				{
					x = Math.floor(tipX);
					y = Math.floor(tipY);
				}
				if (dir != _dir)
				{
					_dir = dir;
					draw();
				}
				event.updateAfterEvent();
			};
			var mouseOver:Function = function (event:MouseEvent):void
			{
				show();
				target.addEventListener(MouseEvent.MOUSE_MOVE, mouseMove, false, 0, true);
			};
			var mouseOut:Function = function (event:MouseEvent):void
			{
				hide();
				target.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMove);
			};
			var remove:Function = function (event:Event):void
			{
				hide();
				target.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMove);
			};
			_targets[target].mouseOver = mouseOver;
			_targets[target].mouseOut = mouseOut;
			_targets[target].mouseMove = mouseMove;
			_targets[target].remove = remove;
			target.addEventListener(MouseEvent.ROLL_OVER, mouseOver, false, 0, true);
			target.addEventListener(MouseEvent.ROLL_OUT, mouseOut, false, 0, true);
			target.addEventListener(Event.REMOVED_FROM_STAGE, remove, false, 0, true);
		}
		
		private function removeEvent(target:DisplayObject):void
		{
			target.removeEventListener(MouseEvent.ROLL_OVER, _targets[target].mouseOver);
			target.removeEventListener(MouseEvent.ROLL_OUT, _targets[target].mouseOut);
			target.removeEventListener(MouseEvent.MOUSE_MOVE, _targets[target].mouseMove);
			target.removeEventListener(Event.REMOVED_FROM_STAGE, _targets[target].remove);
		}
		
		private function clearTarget(target:DisplayObject):void
		{
			if (target == null)
			{
				throw new Error("targe is null");
			}
			if (_targets[target])
			{
				removeTarget(target);
			}
		}
		
		public function updateTarget(target:DisplayObject = null):void
		{
			draw();
		}
		
		private function show():void
		{
			
			if (_parent)
			{
				_parent.addChild(this);
			}
			if (x == 0 && y == 0)
			{
				x = 10000;
				y = 10000;
			}
		}
		
		public function hide():void
		{
			_target = null;
			_content = null;
			graphics.clear();
			if (_parent && parent)
			{
				parent.removeChild(this);
			}
			while (numChildren)
			{
				removeChildAt(0);
			}
		}
		
		private function draw():void
		{
			var addonX:int;
			var addonY:int;
			var i:int;
			if (_target == null || !_targets[_target]["needBg"])
			{
				return;
			}
			graphics.clear();
			var handler:Function = function (index:int):void
			{
				var d:DisplayObject = _targets[_target]["contents"][index];
				visible = d.visible;
				var dWidth:Number = d ? (d.width + _contentOffset.x * 2):(100);
				var dHeight:Number = d ? (d.height + _contentOffset.y * 2):(50);
				var round:int = 3;
				graphics.beginFill(0, 0.75);
				graphics.drawRoundRect(2 + addonX, 2 + addonY, dWidth, dHeight, round, round);
				graphics.endFill();
				graphics.lineStyle(1, 0x1c5538);
				graphics.beginFill(0xFFFFFF);
				graphics.drawRoundRect(0 + addonX, 0 + addonY, dWidth, dHeight, round, round);
				graphics.endFill();
				d.x = _contentOffset.x + addonX;
				d.y = _contentOffset.y + addonY;
				addonX = addonX + (dWidth + 5);
				addonY = addonY + _contentSpan.y;
			};
			var start:int = 0;
			var end:int = _targets[_target]["contents"].length;
			if (TipCtrl.LEFT == _dir)
			{
				i = (end - 1);
				while (i >= start)
				{
					handler(i);
					i = (i - 1);
				}
			}
			else
			{
				i = start;
				while (i < end)
				{
					
					handler(i);
					i = (i + 1);
				}
			}
		}
		/**
		 * 添加浮动提示文字，有其他提示则替换当前提示
		 * @param msg 添加内容
		 * @param target 添加到的容器  如果为null  则添加到舞台
		 * @param x 如果x，y同时为0则设置在容器中心
		 * @param y
		 * @param center 文字是否居中对齐
		 * @param color
		 * @param size
		 * 
		 */		
		public function floatTip(msg:String, target:DisplayObject = null, x:int = 0, y:int = 0, center:Boolean = true, color:uint = 0xffff00, size:int = 20):void
		{
			if(!_txtTween)
				_txtTween = initTextTip();
			setFloatTip(_txtTween, target, x, y, center);
		}
		/**
		 * 添加单独的浮动提示， 与其他提示不冲突 , 内容可以为string 或者 displayObject
		 * @param msg
		 * @param target
		 * @param x
		 * @param y
		 * @param center
		 * @param color
		 * @param size
		 * 
		 */		
		public function floatAloneTip(tip:Object, target:DisplayObject = null, x:int = 0, y:int = 0, center:Boolean = true, color:uint = 0xffff00, size:int = 20):void
		{
			var dis:DisplayObject;
			if(tip is String)
			{
				var field:TextField = initTextTip();
				dis = field;
			}
			else
				dis = tip as DisplayObject;
			setFloatTip(dis, target, x, y, center);
		}
		
		private function setFloatTip(dis:DisplayObject, target:DisplayObject = null, x:int = 0, y:int = 0, center:Boolean = true):void
		{
			var obj:Object = new Object();
			obj.dis = dis;
			obj.angle = 0;
			_floatTipDic[dis] = obj;
			
			dis.alpha = obj.angle;
			
			if(target)
			{
				if(x == 0 && y == 0)
				{
					dis.x = target.x + (target.width - dis.width) / 2;
					dis.y = target.y - 27;
				}
				else
				{
					if(center)
						dis.x = x - dis.width / 2;
					else
						dis.x = x;
					dis.y = y;
				}
				target.parent.addChild(dis);
			}
			else if(_parent && _parent.stage)
			{
				if(x == 0 && y == 0)
				{
					dis.x = (_parent.stage.stageWidth - dis.width) / 2;
					dis.y = (_parent.stage.stageHeight - dis.height) / 3;
				}
				else
				{
					if(center)
						dis.x = x - dis.width / 2;
					else
						dis.x = x;
					dis.y = y;
				}
				_parent.stage.addChild(dis);
			}
			if(dis.stage)
				dis.addEventListener(Event.ENTER_FRAME, enterFrame);
		}
		
		private function initTextTip():TextField
		{
			var textfield:TextField = new TextField();
			textfield.mouseEnabled = false;
			textfield.autoSize = TextFieldAutoSize.LEFT;
			
			return textfield;
		}
		
		
		
		private function enterFrame(event:Event):void
		{
			var dis:DisplayObject = event.currentTarget as DisplayObject;
			var obj:Object = _floatTipDic[dis];
			
			var temp:Number = Math.sin(obj.angle);
			dis.alpha = temp;
			obj.angle = obj.angle + _speed;
			if (obj.angle >= 1.5)
			{
				dis.y = dis.y - obj.angle;
			}
			if (obj.angle >= 3.2)
			{
				obj.angle = 0;
				dis.removeEventListener(Event.ENTER_FRAME, enterFrame);
				if(dis.parent)
					dis.parent.removeChild(dis);
				delete _floatTipDic[dis];
			}
		}
		
		public function set oParent(sp:Sprite):void
		{
			_parent = sp;
		}
		
		public function get targets():Dictionary
		{
			return _targets;
		}
		
		override public function toString():String
		{
			var index:int = 1;
			var placeholder:String = "============\n";
			for (var obj:Object in _targets)
			{
				
				placeholder = placeholder + ("[" + index + "], " + obj + ":\n" + "\tname  :" + obj.name + "\n" + "\tparent:" + obj.parent + "\n" + "\n");
				index++;
			}
			placeholder = placeholder + "============\n";
			return placeholder;
		}
		
		public static function set offset(point:Point):void
		{
			_offset = point;
		}
		
		public static function getInstance():TipCtrl
		{
			if (!_obj)
			{
				_obj = new TipCtrl();
			}
			return _obj;
		}
		
	}
}
